package model;

import java.io.*;
import java.util.*;

public class TockDeck implements Serializable, TockConstants{
	private static final long serialVersionUID = 0; // What the hell is this??
	
	private int currentHand;
	private int num_players;
	private ArrayList<String> deck;
	private ArrayList<ArrayList<String>> hands;
	private boolean doneDeck;
	
	public boolean deckDone() { return doneDeck; }
	public ArrayList<ArrayList<String>> getHands() { return hands; }
	public ArrayList<String> getHand(int index) { return hands.get(index); }
	public int getSize() { return deck.size(); }
		
	
	public TockDeck(int players) {
		currentHand = 0;
		deck = newDeck();
		doneDeck = false;
		
		hands = new ArrayList<ArrayList<String>>();
		for (int i = 0; i < players; i++) {
			hands.add(new ArrayList<String>());
		}
		
		num_players = players;
	}
	
	/**
	 * Creates a new shuffled deck
	 * @return
	 */
	public ArrayList<String> newDeck() {
		if (STACK_DECK) return createStackedDeck();
		
		ArrayList<String> theDeck = new ArrayList<String>();
		ArrayList<String> preDeck = createDeck();
		int max = preDeck.size();
		for (int i = 0; i < max; i++) {
			int num = (int)((Math.random())*preDeck.size());
			theDeck.add(preDeck.get(num));
			preDeck.remove(num);
		}
		return theDeck;
	}
	
	/**
	 * This method deals the deck. Duh...who the hell reads these anyways?
	 *
	 */
	public void deal() {
		clearHands();
		
		for (int i = 0; i < HAND_VALUES[num_players][currentHand]; i++) {
			for (int j = 0; j < hands.size(); j++) {
				hands.get(j).add(deck.get(0));
				deck.remove(0);
			}
		}
		currentHand++;
		if (HAND_VALUES[num_players].length == currentHand) doneDeck = true;
		if (DEBUG_DEALING) System.out.println("New dealing of " + HAND_VALUES[num_players][currentHand-1] + 
				" cards. Current hand is " + currentHand + ". Deck done is " + doneDeck);
	}
	
	/**
	 * Deals a card to a specified player
	 * @param sender The player who gets the next card from the deck
	 */
	public void dealCard(int sender) {
		String card = deck.remove(0);
		hands.get(sender).add(card);
		if (DEBUG_DEALING) System.out.println("Dealing card to " + sender + ": " + card);
	}
	
	/**
	 * Uses a given card for a player
	 * @param sender The player who used the card
	 * @param card The number of the card from 1 to 55
	 */
	public void useCard(int sender, int card) {
		ArrayList<String> hand = getHand(sender);
		
		for (int i=0; i<hand.size(); i++) {
			if (card == Integer.parseInt(hand.get(i))) {
				hand.remove(i);
				if (DEBUG_DEALING) System.out.println("Using card " + card + " for " + sender);
				return;
			}
		}
	}
	
	/**
	 * Clears the hands of all cards
	 *
	 */
	public void clearHands() {
		for (int k = 0; k < hands.size(); k++) {
			hands.get(k).clear();
		}
	}
	
	/**
	 * Checks to see if we're done the hand or not
	 * @return
	 */
	public boolean handDone() {
		for (int i = 0; i < hands.size(); i++) {
			if (!((hands.get(i)).isEmpty())) return false;
		}
		return true;
	}

	/**
	 * Returns the value of a card. 1-3, -4, 5-13, 25
	 * @param index
	 * @return
	 */
	public static int valueOfCard(int index) {
		//--- Check for jokers
		if (index > 52) return 25;
		
		//--- Get the value of the card between 1-13, inclusive
		int cardInt = ((index-1)%13) + 1;
		
		//--- Handle the -4 case
		if (cardInt == 4) cardInt = -4;
		
		return cardInt;
	}
	
	/**
	 * Checks if a hand has a come out card
	 * @param hand
	 * @return
	 */
	public static boolean hasComeOutCard(ArrayList hand) {
		for (int i = 0; i < hand.size(); i++) {
			int tempCard = Integer.parseInt((String)hand.get(i));
			int card = valueOfCard(tempCard);
			if (isComeOutCard(card)) return true;
		}
		return false;
	}
	
	/**
	 * Check for if a card is a come-out card or not
	 * @param card Card value (1-13, 25)
	 * @return
	 */
	public static boolean isComeOutCard(int card) {
		if ((card == 1) || (card == 13) || (card > 13)) return true;
		else return false;
	}
	
	/**
	 * Returns an ArrayList of the strings from 1 to 55 representing cards.
	 * @return
	 */
	public static ArrayList<String> createDeck() {
		ArrayList<String> newDeck = new ArrayList<String>();
		for (int i=1; i<=55; i++) {
			newDeck.add(""+i);
		}		
		return newDeck;
	}
	
	/**
	 * Stacks the deck for testing. Used if the "stackDeck" variable is set
	 * @return an ArrayList of the strings from 1 to 55
	 */
	public static ArrayList<String> createStackedDeck() {
		ArrayList<String> newDeck = new ArrayList<String>();
		
		newDeck.add("53");
		newDeck.add("53");
		newDeck.add("10");
		newDeck.add("8");
		newDeck.add("4");
		newDeck.add("53");
		newDeck.add("7");
		newDeck.add("7");
		
		
		for (int i=newDeck.size()+1; i<=55; i++) {
			newDeck.add(""+i);
		}
		
		return newDeck;
	}
	
	
	public static void main(String args[]) {
		TockDeck bla = new TockDeck(4);
		System.out.println(bla.getHands());
		System.out.println(bla.deckDone());
		bla.deal();
		System.out.println(bla.getHands());
		System.out.println(bla.deckDone());
		bla.deal();
		System.out.println(bla.getHands());
		System.out.println(bla.deckDone());
		bla.deal();
		System.out.println(bla.getHands());
		System.out.println(bla.deckDone());
		bla.deal();
		System.out.println(bla.getHands());
		System.out.println(bla.deckDone());
	}
		
}
